package cn.com.aiouyi.exception.handler;

import cn.com.aiouyi.common.ExceptionCode;
import cn.com.aiouyi.common.Message;
import cn.com.aiouyi.exception.business.BusinessException;
import cn.com.aiouyi.exception.business.BusinessRecordException;
import cn.com.aiouyi.exception.system.SystemException;
import cn.com.aiouyi.util.LogHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * 全局异常处理器
 * @author hanson
 *
 */
@ControllerAdvice
@ResponseBody
@Slf4j
public class ExceptionHandlerAdvice {

	/**
	 * 处理业务异常
	 * @return
	 */
	@ExceptionHandler(value = BusinessException.class)
	public Message handleBussinessException(BusinessException exception, HttpServletRequest request, HttpServletResponse response){
		
		String str = LogHelper.logger(LogHelper.Type.ERROR, exception.getExceptionCode(), exception, "发生业务异常", exception.getData(), true, false);

		log.error(str, exception);
		
		return Message.error(Message.CODE_BUSSINESS_ERROR, exception.getMessage());
	}
	
	/**
	 * 处理业务异常（异常记录数据库）
	 * @return
	 */
	@ExceptionHandler(value = BusinessRecordException.class)
	public Message handleBusinessRecordException(BusinessRecordException exception, HttpServletRequest request, HttpServletResponse response){
		
		String str = LogHelper.logger(LogHelper.Type.ERROR, exception.getExceptionCode(), exception,  "发生业务异常", exception.getData(), true, true);
		
		log.error(str, exception);
		
		return Message.error(Message.CODE_BUSSINESS_ERROR, exception.getMessage());
	}
	
	/**
	 * 处理系统异常
	 * @return
	 */
	@ExceptionHandler(value = SystemException.class)
	public Message handleSystemException(SystemException exception, HttpServletRequest request, HttpServletResponse response){
		
		String str = LogHelper.logger(LogHelper.Type.ERROR, exception.getExceptionCode(), exception, "发生系统异常", null, false, true);
		
		log.error(str, exception);
		
		return Message.error(Message.CODE_SYSTEM_ERROR, exception.getMessage());
	}
	
	/**
	 * 404处理
	 * @param req
	 * @param e
	 * @return
	 * @throws Exception
	 */
	@ExceptionHandler(value = NoHandlerFoundException.class) 
	  public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception { 
	    ModelAndView mav = new ModelAndView("/common/404"); 
	    mav.addObject("exception", e); 
	    mav.addObject("requestUrl", req.getRequestURL()); 
	    return mav; 
	  } 
	
	/**
	 * 处理其它系统异常
	 * @return
	 */
	@ExceptionHandler(value = Exception.class)
	public Message handleException(Exception exception, HttpServletRequest request, HttpServletResponse response){
		
		String str = LogHelper.logger(LogHelper.Type.ERROR, ExceptionCode.ExceptionError, exception, "发生系统异常", null, true ,true);
		
		log.error(str, exception);
		
		return Message.error(Message.CODE_SYSTEM_ERROR, exception.getMessage());
	}
	
	/**
	 * 处理requestMapping 的参数校验绑定异常
	 * @param exception
	 * @param request
	 * @param response
	 * @return
	 */
	@ExceptionHandler(value = {BindException.class, ConstraintViolationException.class})
	public Message handleBindException(Exception exception, HttpServletRequest request, HttpServletResponse response){
		StringBuffer sb = new StringBuffer();
		if(exception instanceof BindException){
			BindException bindException = (BindException)exception;
			List<ObjectError> allErrors = bindException.getAllErrors();
			allErrors.forEach((error) -> {
				sb.append(error.getDefaultMessage() + ";");
			});
		}else if(exception instanceof ConstraintViolationException){
			ConstraintViolationException constraintViolationException = (ConstraintViolationException)exception;
			Set<ConstraintViolation<?>> constraintViolations = constraintViolationException.getConstraintViolations();
			constraintViolations.forEach((constraintViolation) -> {
				sb.append(constraintViolation.getMessage() + ";");
			});
		}
		
		return Message.error(sb.toString());
	}
	
	/**
     * 权限不足报错拦截
     * @return
     * @throws Exception
     */
    @ExceptionHandler(UnauthorizedException.class)
    public Message handleUnauthorizedExceptionHandler(){
        return Message.error(Message.CODE_NO_AUTHORIZED, "common.message.noAuthorized");
    }

    /**
     * 未登录报错拦截
     * 在请求需要权限的接口,而连登录都还没登录的时候,会报此错
     *
     * @return
     * @throws Exception
     */
    @ExceptionHandler(UnauthenticatedException.class)
    public Message handleUnauthenticatedException(UnauthenticatedException exception){
    	exception.printStackTrace();
        return Message.error(Message.CODE_NOT_LOGIN, "common.message.notLogin");
    }
}
